package com.jkgh.remedium.rsgen.generator.flash;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

import com.jkgh.remedium.rsgen.vo.DataObject;
import com.jkgh.remedium.rsgen.vo.FieldInfo;

public class RemediumDataObjectFlashGenerator {

	private static final Map<String, String> DEFAULT_BY_TYPE = new HashMap<String, String>();

	static {

		DEFAULT_BY_TYPE.put("byte", "0");
		DEFAULT_BY_TYPE.put("int", "0");
		DEFAULT_BY_TYPE.put("double", "0.0");
	}

	public static void generate(File outputDir, DataObject d, String packageName) throws FileNotFoundException {

		File outFile = new File(outputDir, d.getClassName() + ".as");
		PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));

		out.println("package " + packageName + " {");
		out.println();
		out.println("	import com.jkgh.remedium.*;");
		out.println("	import com.jkgh.remedium.objects.*;");
		out.println("	import com.jkgh.remedium.objects.messages.*;");
		out.println("	import com.jkgh.remedium.objects.messages.ins.*;");
		out.println("	import com.jkgh.remedium.objects.messages.out.*;");
		out.println("	import com.jkgh.remedium.states.*;");
		out.println("	import com.jkgh.remedium.tools.*;");
		out.println();
		out.println("	/**");
		out.println("	 * " + d.getDescription());
		out.println("	 * ");
		out.println("	 * @author RS2FGenerator");
		out.println("	 *");
		out.println("	 */");
		out.println("	public class " + d.getClassName() + " extends RemediumDataObject {");
		out.println();

		for (FieldInfo f : d.getFields()) {
			out.println("		/**");
			out.println("		 * " + f.getDescription());
			out.println("		 */");
			out.println("		public var " + f.getName() + ":" + f.getClassName() + ";");
			out.println();
		}

		out.println("		/**");
		out.println("		 * General purpose constructor.");
		out.println("		 * ");

		for (FieldInfo f : d.getFields()) {
			out.println("		 * @param " + f.getName() + " " + f.getDescription());
		}

		String fieldsList = "";
		for (FieldInfo f : d.getFields()) {
			fieldsList += f.getName() + ":" + f.getClassName() + " = " + typeToDefault(f.getClassName()) + ", ";
		}
		fieldsList = fieldsList.substring(0, Math.max(0, fieldsList.length() - 2));

		out.println("		 */");
		out.println("		public function " + d.getClassName() + "(" + fieldsList + ") {");
		for (FieldInfo f : d.getFields()) {
			out.println("			this." + f.getName() + " = " + f.getName() + ";");
		}
		out.println("		}");
		out.println();
		out.println("		// --------------------------------------------------------------------------------");
		out.println();
		out.println("		override public function produceContent(remedium:RemediumSystem, message:RemediumOutMessage):void {");
		for (FieldInfo f : d.getFields()) {
			out.println("			" + RemediumProducerFlashGenerator.generate(f.getClassName(), f.getName(), "message") + ";");
		}
		out.println("		}");
		out.println();
		out.println("		public static function createConsumingState(message:RemediumInMessage, future:Function):RemediumState {");
		out.println("			return new GatheringState(1, function(remedium:RemediumSystem):void {");
		out.println();
		out.println("				switch (remedium.produceByte()) {");
		out.println();
		out.println("					case RemediumConstants.NULL:");
		out.println("						future(null);");
		out.println("						break;");
		out.println();
		out.println("					case RemediumConstants.HISTORY:");
		out.println("						future(" + d.getClassName() + "(message.fromHistory(remedium.produceInt())));");
		out.println("						break;");
		out.println();
		out.println("					case RemediumConstants.VALUE:");
		out.println("						consumeContent(remedium, message, future);");
		out.println("						break;");
		out.println("				}");
		out.println("			});");
		out.println("		}");
		out.println();
		out.println("		public static function createVectorConsumingState(message:RemediumInMessage, future:Function):RemediumState {");
		out.println("			return new GatheringState(4, function(remedium:RemediumSystem):void {");
		out.println();
		out.println("				var length:int = remedium.produceInt();");
		out.println("				if (length == -1) {");
		out.println("					future(null);");
		out.println("				} else if (length == 0) {");
		out.println("					future(new Vector.<" + d.getClassName() + ">());");
		out.println("				} else {");
		out.println("					var i:int = 0;");
		out.println("					var result:Vector.<" + d.getClassName() + "> = new Vector.<" + d.getClassName() + ">(length, true);");
		out.println("					var onO:Function = function(o:" + d.getClassName() + "):void {");
		out.println("						result[i++] = o;");
		out.println("						if (i == length) {");
		out.println("							future(result);");
		out.println("						} else {");
		out.println("							remedium.setState(createConsumingState(message, onO));");
		out.println("						}");
		out.println("					};");
		out.println("					remedium.setState(createConsumingState(message, onO));");
		out.println("				}");
		out.println("			});");
		out.println("		}");
		out.println();
		out.println("		private static function consumeContent(remedium:RemediumSystem, message:RemediumInMessage, future:Function):void {");
		out.println("			var ret:" + d.getClassName() + " = new " + d.getClassName() + "();");
		out.println("			message.toHistory(ret);");
		RemediumConsumerFlashGenerator.generate(out, 3, d.getFields(), "future(ret);");
		out.println("		}");
		out.println("	}");
		out.println("}");

		out.close();
	}

	private static String typeToDefault(String className) {

		String ret = DEFAULT_BY_TYPE.get(className);
		if (ret == null) {
			ret = "null";
		}
		return ret;
	}
}
